home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / crossedit / Edit.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  44KB  |  1,779 lines

  1. /*
  2.  *  CrossEdit - game world editor
  3.  *  Copyright (C) 1993 Jarkko Sonninen & Petri Heinila
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  The authors can be reached via e-mail to Jarkko.Sonninen@lut.fi
  20.  *  or Petri.Heinila@lut.fi .
  21.  */
  22.  
  23. #include "Defines.h"
  24. #include "Edit.h"
  25.  
  26. #include "X11.h"
  27. #include "Ansi.h"
  28.  
  29. #include "debug.h"
  30.  
  31. #include "CrList.h"
  32. #include "CrEdit.h"
  33.  
  34. #include "Cnv.h"
  35. #include "App.h"
  36. #include "Attr.h"
  37. #include "Str.h"
  38. #include "Bitmaps.h"
  39.  
  40. /**********************************************************************
  41.  * inner declarations
  42.  **********************************************************************/
  43.  
  44. /*
  45. static void CbEditSetPath (Widget w, XtPointer client, XtPointer call);
  46. static void EditRefreshCb (Widget w, XtPointer client, XtPointer call);
  47. static void CbEditStart (Widget w, XtPointer client, XtPointer call);
  48.  
  49. static void CbEditToggleRead (Widget w, XtPointer client, XtPointer call);
  50. static void CbEditToggleOver (Widget w, XtPointer client, XtPointer call);
  51. static void CbEditToggleAuto (Widget w, XtPointer client, XtPointer call);
  52.  */
  53. /*
  54. static Boolean EdFreeMap ( Edit *);
  55. static Boolean Load ( Edit *, char *name );
  56. static int EdSelectItem ( Edit *, int x, int y );
  57. */
  58. static Boolean EdSaveMap (Edit self, char *name);
  59. /*
  60. static void EditResizeScroll(Edit self,int width,int height,int dx,int dy);
  61. */
  62. static void EditInsertArch (Edit self, int x, int y, int i, archetype * at);
  63.  
  64. object *EditCloneInsert (Edit self,object *obj,int x, int y, int z);
  65. Boolean EditObjectDelete (Edit self, int x, int y, int z);
  66.  
  67. /*
  68.  * getValue functions
  69.  *
  70.  */
  71.  
  72. static void getX (object *ob, char *str, XtPointer c) {
  73.     sprintf(str,"%d",EXIT_X(ob));
  74. }
  75.  
  76. static void getY (object *ob, char *str, XtPointer c) {
  77.     sprintf(str,"%d",EXIT_Y(ob));
  78. }
  79.  
  80. static void getWidth (object *ob, char *str, XtPointer c) {
  81.     sprintf(str,"%d",ob->x);
  82. }
  83.  
  84. static void getHeight (object *ob, char *str, XtPointer c) {
  85.     sprintf(str,"%d",ob->y);
  86. }
  87.  
  88. static void getPath (object *ob, char *str, XtPointer c) {
  89.     Edit edit = (Edit)c;
  90.     strcpy (str, edit->emap->path);
  91. }
  92.  
  93. static void getStacking (object *ob, char *str, XtPointer c) {
  94.     Cardinal stacking;
  95.     Edit edit = (Edit)c;
  96.  
  97.     XtVaGetValues (edit->w, XtNstacking, &stacking, NULL);
  98.     sprintf (str, "%d", stacking);
  99. }
  100.  
  101. static void getTimeout (object *ob, char *str, XtPointer c) {
  102.     sprintf(str,"%d", ob->value);
  103. }
  104.  
  105. static void getReset (object *ob, char *str, XtPointer c) {
  106.     sprintf(str,"%ld", ob->weight);
  107. }
  108.  
  109. static void getDarkness (object *ob, char *str, XtPointer c) {
  110.     sprintf(str,"%d", ob->invisible);
  111. }
  112.  
  113. static void getDifficulty (object *ob, char *str, XtPointer c) {
  114.     sprintf(str,"%d", ob->level);
  115. }
  116.  
  117. static void getOverwrite (object *ob, char *str, XtPointer c) {
  118.     Edit edit = (Edit)c;
  119.     *str = edit->overwrite ? ~0 : 0;
  120. }
  121.  
  122. static void getChoose (object *ob, char *str, XtPointer c) {
  123.     Edit edit = (Edit)c;
  124.     *str = edit->auto_choose ? ~0 : 0;
  125. }
  126.  
  127. static void getReadOnly (object *ob, char *str, XtPointer c) {
  128.     Edit edit = (Edit)c;
  129.     *str = edit->read_only ? ~0 : 0;
  130. }
  131.  
  132. static void getNoReset (object *ob, char *str, XtPointer c) {
  133.     *str = (QUERY_FLAG(ob, FLAG_STAND_STILL))? ~0 : 0;
  134. }
  135.  
  136. static void getShowWeakWalls(object *ob, char *str, XtPointer c) {
  137.     Cardinal weak_walls;
  138.     Edit edit = (Edit)c;
  139.  
  140.     XtVaGetValues (edit->w, XtNshow_weak_walls, &weak_walls, NULL);
  141.     *str= weak_walls ? ~0 : 0;
  142. }
  143.  
  144. /*
  145.  * putValue functions
  146.  *
  147.  */
  148.  
  149. static int new_x, new_y;
  150.  
  151.  
  152. /*** coord ***/
  153. static void putX (object *ob, char *str, XtPointer c) {
  154.     EXIT_X(ob) = atoi(str);
  155. }
  156.  
  157. static void putY (object *ob, char *str, XtPointer c) {
  158.     EXIT_Y(ob) = atoi(str);
  159. }
  160.  
  161. /*** path ***/
  162. static void putPath (object *ob, char *str, XtPointer c) {
  163.     Edit edit = (Edit)c;
  164.     strcpy (edit->emap->path, str);
  165. }
  166.  
  167. /*** size ***/
  168. static void putWidth (object *ob, char *str, XtPointer c) {
  169.     new_x = atoi(str);
  170. }
  171. static void putHeight (object *ob, char *str, XtPointer c) {
  172.     new_y = atoi(str);
  173. }
  174.  
  175. static void putStacking (object *ob, char *str, XtPointer c) {
  176.     Edit edit = (Edit)c;
  177.     int stacking = atoi(str);
  178.  
  179.     if (stacking > 48) {
  180.     CnvNotify ("Illegal space","Ok",NULL);
  181.     return;
  182.     }
  183.     XtVaSetValues(edit->w,XtNstacking,stacking,NULL);
  184. }
  185.  
  186. static void putOverwrite (object *ob, char *str, XtPointer c) {
  187.     Edit edit = (Edit)c;
  188.     edit->overwrite = *str;
  189. }
  190.  
  191. static void putReadOnly (object *ob, char *str, XtPointer c) {
  192.     Edit edit = (Edit)c;
  193.     edit->read_only = *str;
  194.  
  195.  
  196.     /* kludge */
  197.     /* this function will be called last in this list */
  198.     if (new_y != ob->y || new_x != ob->x) {
  199.     /* update map window */
  200.     EditResizeScroll (edit, new_x, new_y, 0, 0);
  201.     } else {
  202.     EditUpdate (edit);
  203.     }
  204. }
  205.  
  206. static void putChoose (object *ob, char *str, XtPointer c) {
  207.     Edit edit = (Edit)c;
  208.     edit->auto_choose = *str;
  209. }
  210.  
  211. static void putTimeout (object *ob, char *str, XtPointer c) {
  212.     ob->value = atoi(str);
  213. }
  214.  
  215. static void putReset (object *ob, char *str, XtPointer c) {
  216.     ob->weight = atoi(str);
  217. }
  218.  
  219. static void putDarkness (object *ob, char *str, XtPointer c) {
  220.     ob->invisible = atoi(str);
  221. }
  222.  
  223. static void putDifficulty (object *ob, char *str, XtPointer c) {
  224.     ob->level = atoi(str);
  225. }
  226.  
  227. static void putNoReset(object *ob, char *str, XtPointer c) {
  228.     if (*str) SET_FLAG(ob,FLAG_STAND_STILL);
  229.     else CLEAR_FLAG(ob, FLAG_STAND_STILL);
  230. }
  231.  
  232. static void putShowWeakWalls (object *ob, char *str, XtPointer c) {
  233.     Edit edit = (Edit)c;
  234.     Cardinal weak_walls;
  235.  
  236.     if (*str) weak_walls=1;
  237.     else weak_walls=0;
  238.  
  239.     XtVaSetValues(edit->w,XtNshow_weak_walls,weak_walls,NULL);
  240. }
  241.  
  242.  
  243. /**********************************************************************
  244.  * tags
  245.  **********************************************************************/
  246.  
  247. static AttrDef MapDescription[] = {
  248.     {"Path",        TypeString, getPath,        putPath},
  249.     {"Start X",        TypeString, getX,        putX},
  250.     {"Start Y",        TypeString, getY,        putY},
  251.     {"Width",        TypeString, getWidth,        putWidth},
  252.     {"Height",        TypeString, getHeight,        putHeight},
  253.     {"Stacking",    TypeString, getStacking,    putStacking},
  254.     {"Timeout",        TypeString, getTimeout,        putTimeout},
  255.     {"Reset",        TypeString, getReset,        putReset},
  256.     {"Difficulty",    TypeString, getDifficulty,    putDifficulty},
  257.     {"Darkness",    TypeString, getDarkness,    putDarkness},
  258.     {"FixedReset",    TypeToggle, getNoReset,        putNoReset},
  259.     {"Show Weak Walls",    TypeToggle, getShowWeakWalls,    putShowWeakWalls},
  260.     /* Make sure the ReadOnly is the last thing on the list, otherwise
  261.      * things won't work properly.
  262.      */
  263.     {"ReadOnly",    TypeToggle, getReadOnly,    putReadOnly},
  264.     {NULL,        TypeString, 0,            0},
  265.     {"Overwrite",    TypeToggle, getOverwrite,    putOverwrite},
  266.     {"Choose",        TypeToggle, getChoose,        putChoose},
  267.     {NULL,        0, 0,                0}
  268. };
  269.  
  270.  
  271. /*
  272.  * to all refresh  
  273.  */
  274. const XRectangle EditRectAll = {
  275.     0,0,
  276.     10000,10000
  277. };
  278.  
  279. /**********************************************************************
  280.  * privates
  281.  **********************************************************************/
  282.  
  283. /*
  284.  *
  285.  */
  286. static Boolean EdFreeMap (Edit self)
  287. {
  288.     if (!self) return False;
  289.     
  290.     /*** no item from self map anymore ***/
  291.     if (AppItemGetEdit(self->app) == self) {
  292.     AppItemSet (self->app, NULL,NULL,0);
  293.     }
  294.     if(self->app->look.edit == self)
  295.     AppSelectUnset(self->app);
  296.     if (self->emap) {
  297.     *self->emap->path = '\0';
  298.     free_map (self->emap, 1);
  299.     delete_map (self->emap);
  300.     self->emap = NULL;
  301.     }
  302.     return True;
  303. }
  304.  
  305. /*
  306.  * member   : load map from file to memory
  307.  *            there should no other map loading function for editor
  308.  *            than self
  309.  * name     : filename of map, relative ( level number )  
  310.  * return   : True, if map is loaded
  311.  */
  312. static Boolean Load(Edit self, char *name)
  313. {
  314.     int mask;
  315.     mapstruct *tmp;
  316.     char path[PATH_MAX+1],save[PATH_MAX+1];
  317.     char buf[BUFSIZ];
  318.     
  319.     strcpy(path, name);
  320.     if((mask = check_path (path)) < 4) {
  321.     sprintf(buf,"You can't access %s",path);
  322.     CnvNotify(buf,"Continue",NULL);
  323.     return False;
  324.     }
  325.  
  326.     /* new map, no refs */
  327.     if(self->app->look.edit == self) {
  328.     AppSelectUnset(self->app);
  329.     AttrChange(self->app->attr,NULL, 0, 0);
  330.     }
  331.     /*** remove old mapstructure ***/
  332.     if(self->emap)
  333.     strcpy(save,self->emap->path); /* klydge */
  334.     EdFreeMap (self);
  335.     if(!(tmp = ready_map_name (path, 1))) {
  336.     sprintf(buf,"Cannot load map %s",path);
  337.     CnvNotify(buf,"Continue",NULL);
  338.     if(!(tmp = ready_map_name(save,1))) return False;
  339.     }
  340.  
  341.     /*** initialiaze map ***/
  342.     debug1("Edit-Load() %s\n",path);
  343.     if(self->view) XawViewportSetLocation(self->view,0,0);
  344.     self->emap = tmp;
  345.     self->read_only = mask & 2 ? 0 : 1;
  346.     strcpy (self->emap->path, path);
  347.     EditUnmodified(self);
  348.     EditUpdate(self);
  349.     CrEditRefresh(self->w,EditRectAll);
  350.     return True;
  351. }
  352.  
  353. /**********************************************************************
  354.  * wall handling
  355.  **********************************************************************/
  356.  
  357. static int direction_x[] = {0, -1, 0, 1};
  358. static int direction_y[] = {1, 0, -1, 0};
  359.  
  360. /*
  361.  *
  362.  */
  363. static int find_draw_arch (mapstruct * emap, int line, archetype * at)
  364. {
  365.     int i;
  366.     object *tmp;
  367.  
  368.     for (i = 0; i < 16; i++)
  369.     if ((tmp = get_map_ob (emap, i, line)) &&
  370.       tmp->arch == at)
  371.         return (i);
  372.     return (-1);
  373. }
  374.  
  375. static void EditInsertArch (Edit self, int x, int y, int i, archetype * at)
  376. {
  377.     Window w;
  378.     mapstruct *emap;
  379.     object *op,*tmp;
  380.     int j = i;
  381.     XRectangle rect;
  382.  
  383.     emap = self->emap;
  384.     w = XtWindow(self->w);
  385.     op = get_map_ob (emap, x, y);
  386.  
  387.     /* check for duplicate object */
  388.     while (op && op->above)
  389.         op = op->above;
  390.     while (op && j-- > 0)
  391.         op = op->below;
  392.     if (op && op->arch == at)
  393.         return;
  394.  
  395.     if (arch_out_of_map (at, self->emap, x, y)) {
  396.         debug("Out of Map\n");
  397.         return;
  398.     }
  399.     op = ObjectCreateArch (at);
  400.     if (op) {
  401.         MapInsertObjectZ(emap,op,x,y,i);
  402.         /*debug3 ("Inserting %s %d %d\n", op->name, op->x, op->y);*/
  403.  
  404.         for (tmp = op; tmp; tmp = tmp->more) {
  405.             if (self->app->look.rect.x == tmp->x && 
  406.         self->app->look.rect.y == tmp->y)
  407.                 AppUpdate(self->app);
  408.         }
  409.     rect.x = x;
  410.     rect.y = y;
  411.     rect.width = rect.height = 1;
  412.     CrEditRefresh(self->w,rect);
  413.     } else {
  414.         free_object (op);
  415.         debug0 ("Inserting failed\n");
  416.     }
  417.  
  418.     return;
  419. }
  420.  
  421. /*
  422.  * member: hmm
  423.  */
  424. static int update_wall (Edit self, int x, int y, int add, int rem)
  425. {
  426.     int i;
  427.     object *tmp, *op;
  428.     Window w;
  429.     mapstruct * emap;
  430.     
  431.     emap = self->emap;
  432.     w = XtWindow(self->w);
  433.  
  434.     if (out_of_map (emap, x, y) || !(op = get_map_ob (emap, x, y)))
  435.     return False;
  436.  
  437.     while (op->above)
  438.     op = op->above;
  439.  
  440.     /*
  441.     i = find_draw_arch (self->app->item.wall_map, 
  442.             self->app->item.wall_set, 
  443.             op->arch);
  444.             */
  445.     i = find_draw_arch (AppItemGetMap(self->app), 
  446.             AppItemGetWall(self->app), 
  447.             op->arch);
  448.     if (i >= 0) {
  449.     /* debug4 ("%d | %d & ~%d = %d\n", i, add, rem, (i | add) & ~rem); */
  450.     remove_ob (op);
  451.     free_object (op);
  452.     tmp = get_map_ob (AppItemGetMap(self->app), ((i | add) & ~rem),
  453.       AppItemGetWall(self->app));
  454.     if (tmp)
  455.         EditInsertArch (self, x, y, 0, tmp->arch);
  456.     return True;
  457.     }
  458.     return False;
  459. }
  460.  
  461. /*
  462.  *
  463.  */
  464. static void draw_add (Edit self, int x, int y)
  465. {
  466.     int i, mask = 0;
  467.  
  468.     if (!self->app->item.wall_map)
  469.     CnvDie(self->shell,"No Wall map");
  470.  
  471.     if (self->app->item.wall_map->mapx < 16)
  472.     CnvDie(self->shell,"Wall Map has wrong width\n");
  473.  
  474.     for (i = 0; i < 4; i++)
  475.     if (update_wall (self, x + direction_x[i], y + direction_y[i], 
  476.              (1 << i), 0))
  477.         mask |= (1 << (i ^ 2));
  478.  
  479.     update_wall (self, x, y, mask, 0);
  480. }
  481.  
  482. /*
  483.  *
  484.  */
  485. static void draw_remove (Edit self, int x, int y)
  486. {
  487.     if (!self->app->item.wall_map)
  488.     CnvDie(self->shell,"No Wall map");
  489.  
  490.     if (self->app->item.wall_map->mapx < 16)
  491.     CnvDie(self->shell,"Wall Map has wrong width\n");
  492.  
  493.     update_wall (self, x, y + 1, 0, 1);
  494.     update_wall (self, x - 1, y, 0, 2);
  495.     update_wall (self, x, y - 1, 0, 4);
  496.     update_wall (self, x + 1, y, 0, 8);
  497. }
  498.  
  499.  
  500. /*
  501.  * member: resize and scroll mao of editor
  502.  * width : new width, if zero, no resize
  503.  * height: new height, if zero, no resize
  504.  * dx    : amount to scroll, neg. to left, pos. to right
  505.  * dy    : amount to scroll, neg, to up, pos. to down
  506.  */
  507. void EditResizeScroll(Edit self,int width,int height,int dx,int dy)
  508. {
  509.     mapstruct *tmp;
  510.     char buf[BUFSIZ];
  511.  
  512.     if(!self || self->read_only) return;
  513.     if(self->type != ClipBoard &&  
  514.        (width < MapMinWidth || width > MapMaxWidth ||
  515.     height < MapMinHeight || height > MapMaxHeight)) {
  516.     sprintf(buf,"Map cannot be smaller than %dx%d",
  517.         MapMinWidth,MapMinHeight);
  518.     CnvNotify(buf,"Continue",NULL);
  519.     return;
  520.     }
  521.  
  522.  
  523.     /*
  524.      * SelectUnset before EdFreeMap, since, it tries to 
  525.      *  do that, and there's no mapstuct at that moment 
  526.      */
  527.     if(self->app->look.edit == self)
  528.     AppSelectUnset(self->app);
  529.     
  530.     tmp = MapMoveScrollResize(self->emap, width, height, dx, dy);
  531.     self->emap = NULL; /* MapMoveScrollResize destroys the old map */
  532.     EdFreeMap(self);
  533.     self->emap = tmp;
  534.     EditModified(self);
  535.     EditUpdate(self);
  536.  
  537.     CrEditRefresh(self->w,EditRectAll);
  538.  
  539.     debug5("EditResizeScroll() %s %dx%d+%d+%d\n",
  540.        EditGetPath(self),width,height,dx,dy);
  541. }
  542.  
  543. /**********************************************************************
  544.  * File-menu callbacks
  545.  **********************************************************************/
  546.  
  547. /*
  548.  * callback: save current map, ask name if not given
  549.  */
  550. static void SaveCb (Widget w, XtPointer client, XtPointer call)
  551. {
  552.     Edit self = (Edit) client;
  553.     EditSave(self);
  554. }
  555.  
  556. /*
  557.  * callback: save map as name
  558.  */
  559. static void SaveAsCb (Widget w, XtPointer client, XtPointer call)
  560. {
  561.     Edit self = (Edit) client;
  562.     char path[PATH_MAX];
  563.  
  564.     if(CnvPathSelect(self->app->path) == CnvPathCancel) return;
  565.     sprintf(path,"%s/%s",
  566.         self->app->path->current,
  567.         self->app->path->filename);
  568.     EdSaveMap(self,path);
  569. }
  570.  
  571. /*
  572.  * callback: load current map again
  573.  */
  574. static void ClearCb (Widget w, XtPointer client, XtPointer call)
  575. {
  576.     Edit self = (Edit) client;
  577.     Map tmp;
  578.  
  579.     debug1("ClearCb() %s\n",self->emap->path);
  580.     if(self->read_only) return;
  581.     tmp = get_empty_map(self->emap->mapx,self->emap->mapy);
  582.     copy_map (self->emap, tmp); 
  583.     EdFreeMap(self);
  584.     self->emap = tmp;
  585.     EditUnmodified(self);
  586.     EditUpdate(self);
  587. }
  588.  
  589. /*
  590.  * callback: load new map
  591.  */
  592. static void LoadCb (Widget w, XtPointer client, XtPointer call)
  593. {
  594.     Edit self = (Edit) client;
  595.     char path[PATH_MAX+1],buf[BUFSIZ];
  596.  
  597.     /*** save, if modified ***/
  598.     if (self->modified) {
  599.     switch (CnvNotify ("Map modified, save",
  600.                "OK","Cancel","No",NULL)) {
  601.       case 1:
  602.         EditSave(self);
  603.         break;
  604.       case 2:
  605.         return; 
  606.       default:
  607.         break;
  608.     }
  609.     }
  610.     /*** load map ***/
  611.     if(CnvPathSelect(self->app->path) == CnvPathCancel) return;
  612.     sprintf(path,"%s/%s",self->app->path->current,self->app->path->filename);
  613.     /*** check out if map can load ***/
  614.     if (has_been_loaded (path)) {
  615.       sprintf(buf,"%s already in memory",path);
  616.       CnvNotify(buf,"Continue",NULL);
  617.       return;
  618.     }
  619.     Load(self,path);
  620. }
  621.  
  622. /*
  623.  * callback: load current map again
  624.  */
  625. static void ReloadCb (Widget w, XtPointer client, XtPointer call)
  626. {
  627.     Edit self = (Edit) client;
  628.     debug1("ReloadCb() %s\n",self->emap->path);
  629.     Load(self,self->emap->path);
  630. }
  631.  
  632. /* 
  633.  * callback: enter to map in Look window 
  634.  */
  635. static void EnterCb (Widget w, XtPointer client, XtPointer call)
  636. {
  637.     Edit self = (Edit) client;
  638.     object *obj = NULL, *tmp;
  639.     char buf[BUFSIZ];
  640.     char *path,loadPath[PATH_MAX+1];
  641.     XRectangle rect;
  642.     
  643.     /*** find object ***/
  644.     if(self->app->look.edit)
  645.     obj = MapGetObjectZ
  646.         (self->app->look.edit->emap,
  647.          self->app->look.rect.x,
  648.          self->app->look.rect.y,0);
  649.     if (!obj || !self->app->look.edit) {
  650.     CnvNotify("Select exit to enter","Continue",NULL);
  651.     return;
  652.     }
  653.     /*** foreach object in list, if exit load it ***/
  654.     tmp = obj;
  655.     do {
  656.     obj = tmp->head ? tmp->head : tmp;
  657.     if (obj->type == TELEPORTER || obj->type==EXIT) {
  658.         /*** check out if exit leads ***/
  659.         if(!EXIT_PATH(obj)) {
  660.         CnvNotify("Exit leads nowhere",
  661.               "OK",NULL);
  662.         return;
  663.         }
  664.         path = EXIT_PATH(obj);
  665.         rect.x = EXIT_X(obj);
  666.         rect.y = EXIT_Y(obj);
  667.         /*** save current map if modified ***/
  668.         if (self->modified) {
  669.         switch (CnvNotify ("Map modified, save",
  670.                    "Save","Cancel","Forget",NULL)) {
  671.           case 1:
  672.             EditSave(self);
  673.             break;
  674.           case 2:
  675.             return;
  676.           default:
  677.             break;
  678.         }
  679.         }
  680.         /*** load & update ***/
  681.         StrPathCd(strcpy(loadPath,EditGetPath(self)),path);
  682.         debug1("EnterCb() %s\n",loadPath);
  683.  
  684.         /*** check out if map can load ***/
  685.         if (has_been_loaded (loadPath)) {
  686.         sprintf(buf,"%s already in memory",loadPath);
  687.         CnvNotify(buf,"Continue",NULL);
  688.         return;
  689.         }
  690.         if(!Load(self,loadPath)) return;
  691.         if (rect.x == 0 && rect.y == 0) {
  692.         rect.x = EXIT_X(self->emap->map_object);
  693.         rect.y = EXIT_Y(self->emap->map_object);
  694.         }
  695.         rect.width = rect.height = 0;
  696.         AppSelectSet(self->app, self, rect);
  697.         CrEditSelect(self->w, rect);
  698.         return;
  699.     }
  700.     tmp = tmp->below;
  701.     } while(tmp);
  702.     CnvNotify("That's not exit","Continue",NULL);
  703. }
  704.  
  705. /*
  706.  * callback: reset this map from crossfire 
  707.  */
  708. static void ResetCb (Widget w, XtPointer client, XtPointer call)
  709. {
  710.     Edit self = (Edit) client;
  711.     char cmd[ARG_MAX+1],buf[MAX_INPUT+1];
  712.  
  713.     debug0("ResetCb()\n");
  714.     if(!self->app->res.cmdReset) {
  715.     CnvNotify("no defined *cmdReset:","Continue",NULL);
  716.     return;
  717.     }
  718.     sprintf(cmd,self->app->res.cmdReset,EditGetPath(self));
  719.     if(system(cmd)) {
  720.     sprintf(buf,"Command failed \"%s\"",cmd);
  721.     CnvNotify(buf,"Continue",NULL);
  722.     }
  723. }
  724.  
  725. /*
  726.  * callback: quit map editor
  727.  */
  728. static void CloseCb (Widget w, XtPointer client, XtPointer call)
  729. {
  730.     char buf[BUFSIZ];
  731.     Edit self = (Edit) client;
  732.     if (EditIsModified(self)) {
  733.     sprintf (buf, "Quitting, save %s ?", self->emap->path);
  734.     switch (CnvNotify (buf,"Save","Cancel", "Forget",NULL)) {
  735.       case 1:        /* ok */
  736.         EditSave(self);
  737.         break;
  738.       case 2:
  739.         return;
  740.       default:
  741.         EditUnmodified(self); /* to fool EditDestroy */
  742.         break;
  743.     }
  744.     }
  745.     EditDestroy(self);
  746. }
  747.  
  748. static CnvMenuRec fileMenu[] = {
  749.     {"save",   SaveCb},
  750.     {"saveAs", SaveAsCb},
  751.     {"----",   NULL},
  752.     {"load",   LoadCb},
  753.     {"reload", ReloadCb},
  754.     {"----",   NULL},
  755.     {"clear",  ClearCb},
  756.     {"reset",  ResetCb},
  757.     {"----",   NULL},
  758.     {"enter",  EnterCb},
  759.     {"----",   NULL},
  760.     {"close",  CloseCb},
  761.     {"",       NULL },
  762. };
  763.  
  764. /**********************************************************************
  765.  * Auto Creating stuff
  766.  **********************************************************************/
  767.  
  768. static char * MapMessageCreate (App self) {
  769.     char buf[MAX_BUF];
  770.     time_t t = time(NULL);
  771.     sprintf (buf, "Creator: %s\nEmail: %s\nDate: %s", 
  772.          self->res.creator,self->res.email, ctime (&t));
  773.     return add_string (buf);
  774. }
  775.  
  776. static char * MapNameCreate (String path)
  777. {
  778.     char name[PATH_MAX+1];
  779.     int i,j;
  780.  
  781.     strncpy(name,path,PATH_MAX);
  782.     for(i = strlen(name)-1; i && name[i] != '/';i--);
  783.     i++;
  784.     for(j = i; name[j] && name[j] != '.';j++);
  785.     if(name[j] == '.') name[j] = 0;
  786.     return add_string (&name[i]);
  787. }
  788.  
  789. /**********************************************************************
  790.  * Options - menu
  791.  **********************************************************************/
  792.  
  793.  
  794. #if 0
  795. /*
  796.  * callback: set new path of map
  797.  */
  798. static void SetPathCb (Widget w, XtPointer client, XtPointer call)
  799. {
  800.     char path[CnvPromptMax+1];
  801.     Edit self = (Edit) client;
  802.     
  803.     switch (CnvPrompt ("Set path", self->emap->path, path, 
  804.                "OK","Cancel",NULL)) {
  805.     case 1:
  806.     EditSetPath(self,path);
  807.     default:
  808.     break;
  809.     }
  810. }
  811.  
  812. /*
  813.  * callback: resize and scroll map
  814.  */
  815. static void ResizeCb (Widget w, XtPointer client, XtPointer call)
  816. {
  817.     Edit self = (Edit) client;
  818.     char buf[1025], path[CnvPromptMax+1];
  819.     unsigned x, y;
  820.     int sx = 0, sy = 0, res;
  821.  
  822.     if (self->read_only)
  823.     return;
  824.  
  825.     sprintf (buf, "%dx%d+0+0", 
  826.          self->emap->mapx, self->emap->mapy);
  827.     switch (CnvPrompt ("ResizeScroll",
  828.                buf, path,"OK",NULL)) {
  829.     case 1:
  830.     res = XParseGeometry (path, &sx, &sy, &x, &y);
  831.     
  832.     if (!(res & WidthValue))
  833.         x = self->emap->mapx;
  834.     if (!(res & HeightValue))
  835.         y = self->emap->mapy;
  836.     
  837.     if (!(res & XValue))
  838.         sx = 0;
  839.     if (!(res & YValue))
  840.         sy = 0;
  841.  
  842.     if (x < 3 || y < 3 || x > 100 || y > 100) {
  843.         CnvNotify ("Illegal size","OK",NULL);
  844.         return;
  845.     }
  846.     EditResizeScroll (self, x,y,sx, sy);
  847.     break;
  848.     default:
  849.     return;
  850.     }
  851. }
  852.  
  853. /*
  854.  * callback: set start point
  855.  */
  856. static void StartCb (Widget w, XtPointer client, XtPointer call)
  857. {
  858.     Edit self = (Edit) client;
  859.     char buf[BUFSIZ], reply[CnvPromptMax+1];
  860.     int x, y, flags;
  861.     int width, height;
  862.  
  863.     sprintf (buf, "%dx%d", 
  864.          EXIT_X (self->emap->map_object),
  865.          EXIT_Y (self->emap->map_object));
  866.     switch (CnvPrompt ("Start of map", buf,reply,
  867.     "OK","Cancel",NULL)) {
  868.     case 1:            /* ok */
  869.     flags = XParseGeometry (reply, &x, &y, &width, &height);
  870.     if ((flags != (WidthValue | HeightValue))) {
  871.         CnvNotify ( "Illegal value","Ok",NULL);
  872.         return;
  873.     }
  874.     if (out_of_map(self->emap,width,height)) {
  875.         sprintf (buf, "Point  %dx%d out of map", width, height);
  876.         CnvNotify (buf,"OK",NULL);
  877.         return;
  878.     } else {
  879.         EXIT_X(self->emap->map_object) = width;
  880.         EXIT_Y(self->emap->map_object) = height;
  881.         EditModified(self);
  882.     }
  883.     EditUpdate(self);
  884.     return;
  885.     default:
  886.     return;
  887.     }
  888. }
  889. #endif
  890.  
  891. /*
  892.  * Edit attributes of the Map
  893.  */
  894. static void AttributesCb (Widget w, XtPointer client, XtPointer call)
  895. {
  896.     Edit self = (Edit)client;
  897.     
  898.     debug0("Edit::AttributesCb()\n");
  899.  
  900.     if(!self->mapattr) {
  901.     self->mapattr = AttrCreate 
  902.         ("mapattr", self->app, self->emap->map_object, 
  903.          MapDescription, -1, (XtPointer)self);
  904.     } else {
  905.     AttrDestroy(self->mapattr);
  906.     }
  907.     return;
  908. }
  909.  
  910. /* 
  911.  * callback: refresh map
  912.  */
  913. static void RefreshCb (Widget w, XtPointer client, XtPointer call)
  914. {  
  915.   Edit self = (Edit)client;
  916.   CrEditRefresh(self->w,EditRectAll);
  917.   EditUpdate(self);
  918. }
  919.  
  920. #if 0
  921. /* 
  922.  * callback: toggle write accces 
  923.  */
  924. static void ToggleReadCb (Widget w, XtPointer client, XtPointer call)
  925. {
  926.   Edit self = (Edit)client;
  927.  
  928.   if(self->type == Pick ||
  929.      self->type == Wall) return;
  930.   ((Edit) client)->read_only++;
  931.   EditUpdate(self);
  932.   debug ("CbEditToggleRead()\n");
  933. }
  934. #endif
  935.  
  936. /* 
  937.  * callback: Toggle overwrite mode 
  938.  */
  939. static void ToggleOverCb (Widget w, XtPointer client, XtPointer call)
  940. {
  941.   Edit self = (Edit)client;
  942.  
  943.   if(self->type == Pick ||
  944.      self->type == Wall) return;
  945.   ((Edit) client)->overwrite++;
  946.   EditUpdate(self);
  947.   debug ("CbEditToggleOver()\n");
  948. }
  949.  
  950. /* 
  951.  * callback: Toggle auto choose 
  952.  */
  953. static void ToggleAutoCb (Widget w, XtPointer client, XtPointer call)
  954. {
  955.   Edit self = (Edit)client;
  956.  
  957.   if(self->type == Pick ||
  958.      self->type == Wall) return;
  959.   ((Edit) client)->auto_choose++;
  960.   EditUpdate(self);
  961.   debug ("CbEditToggleAuto()\n");
  962. }
  963.  
  964. static Widget OptionMenu(String name,Edit self,Widget parent)
  965. {
  966.     Widget shell,refresh, use;
  967.  
  968.     shell = XtVaCreatePopupShell 
  969.       (name, simpleMenuWidgetClass, parent, NULL);
  970.  
  971.     use = XtVaCreateManagedWidget
  972.     ("attributes",smeBSBObjectClass, shell,
  973.      NULL);
  974.     XtAddCallback(use,XtNcallback,AttributesCb,(XtPointer)self);
  975.  
  976.     /*** refresh ***/
  977.     XtVaCreateManagedWidget ("line", smeLineObjectClass, shell, NULL);
  978.     refresh = XtVaCreateManagedWidget
  979.     ("refresh",smeBSBObjectClass,shell,
  980.      NULL);
  981.     XtAddCallback
  982.     (refresh,XtNcallback,RefreshCb,(XtPointer)self);
  983.     /*** toggles ***/
  984.     XtVaCreateManagedWidget ("line", smeLineObjectClass, shell, NULL);
  985.     self->iw.overwrite = XtVaCreateManagedWidget 
  986.     ("overWrite", smeBSBObjectClass, shell, NULL);
  987.     XtAddCallback (self->iw.overwrite,
  988.            XtNcallback,ToggleOverCb, (XtPointer) self);
  989.     self->iw.auto_choose = XtVaCreateManagedWidget 
  990.     ("autoChoose", smeBSBObjectClass, shell, NULL);
  991.     XtAddCallback (self->iw.auto_choose,
  992.            XtNcallback,ToggleAutoCb, (XtPointer) self);
  993.  
  994.     return shell;
  995. }
  996.  
  997. /**********************************************************************
  998.  * edit routines - CrEdit callbacks
  999.  *   insert
  1000.  *   select
  1001.  *   delete
  1002.  *   align
  1003.  *   feed
  1004.  **********************************************************************/
  1005.  
  1006. static void InsertCb(Widget w,XtPointer clientData,XtPointer callData)
  1007. {
  1008.     Edit self = (Edit)clientData;
  1009.     CrEditCall call = (CrEditCall)callData;
  1010.     AppSelectUnset(self->app);
  1011.     EditInsert(self,call->rect.x,call->rect.y,call->z);
  1012. }
  1013.  
  1014. static void SelectCb(Widget w,XtPointer clientData,XtPointer callData)
  1015. {
  1016.     Edit self = (Edit)clientData;
  1017.     CrEditCall call = (CrEditCall)callData;
  1018.     if(self->auto_choose) {
  1019.     if(self->type == Wall && call->rect.x == 0) {
  1020.         AppItemSet(self->app,self,NULL,call->rect.y);
  1021.     } else {
  1022.         object *obj;
  1023.         obj = MapGetRealObject(self->emap,call->rect.x,call->rect.y,0);
  1024.         AppItemSet(self->app,self,obj,AppItemNoWall);
  1025.     }
  1026.     } else {
  1027.     AppSelectSet(self->app,self,call->rect);
  1028.     }
  1029. }
  1030.  
  1031. static void PropsCb(Widget w,XtPointer clientData,XtPointer callData)
  1032. {
  1033.     Edit self = (Edit)clientData;
  1034.     CrEditCall call = (CrEditCall)callData;
  1035.     debug0 ("PropsCb()\n");
  1036.     if(!self->auto_choose) {
  1037.     object *ob = MapGetRealObject
  1038.         (self->emap, call->rect.x, call->rect.y, call->z);
  1039.     if(!self->app->attr) {
  1040.         self->app->attr = AttrCreate 
  1041.         ("attr", self->app, ob, AttrDescription, GetType(ob), self);
  1042.     } else {
  1043.         AttrChange (self->app->attr,ob, GetType(ob), self);
  1044.     }
  1045.     }
  1046.     return;
  1047. }
  1048.  
  1049. static void DeleteCb(Widget w,XtPointer clientData,XtPointer callData)
  1050. {
  1051.     Edit self = (Edit)clientData;
  1052.     CrEditCall call = (CrEditCall)callData;
  1053.     AppSelectUnset(self->app);
  1054.     EditDelete(self,call->rect.x,call->rect.y,call->z);
  1055. }
  1056.  
  1057. static void AlignCb(Widget w,XtPointer clientData,XtPointer callData)
  1058. {
  1059.     Edit self = (Edit)clientData;
  1060.     CrEditCall call = (CrEditCall)callData;
  1061.     debug4("Edit::AlignCb() by %dx%d+%d+%d\n",call->rect.width,
  1062.        call->rect.height,call->rect.x,call->rect.y);
  1063.     EditResizeScroll(self,call->rect.width,
  1064.              call->rect.height,call->rect.x,call->rect.y);
  1065. }
  1066.  
  1067. static void FeedCb(Widget w,XtPointer clientData,XtPointer callData)
  1068. {
  1069.     Edit self = (Edit)clientData;
  1070.     CrEditCall call = (CrEditCall)callData;
  1071.     char buf[BUFSIZ],*str;
  1072.     
  1073.     debug("FeedCb()\n");
  1074.     /*** path, modified for game, not clean thing  ***/
  1075.     str = buf;
  1076.     if (!self->app->attr || !self->app->attr->op)
  1077.     return;
  1078.     if(!strcmp(self->app->attr->op->map->path,call->map->path)) {
  1079.     StrBasename(buf,self->app->attr->op->map->path);
  1080.     } else {
  1081.     strcpy(buf,self->app->attr->op->map->path);
  1082.     StrPathGenCd(buf,call->map->path);
  1083.     if(strlen(buf) > 2) str = &buf[2];
  1084.     }
  1085.     XtVaSetValues (self->app->attr->tags[I_Path].value, 
  1086.            XtNstring, str, 
  1087.            NULL);
  1088.     /*** x ***/
  1089.     sprintf (buf, "%d", call->rect.x);
  1090.     XtVaSetValues (self->app->attr->tags[I_X].value,
  1091.            XtNstring, buf, 
  1092.            NULL);
  1093.     /*** y ***/
  1094.     sprintf (buf, "%d", call->rect.y);
  1095.     XtVaSetValues (self->app->attr->tags[I_Y].value,
  1096.            XtNstring, buf, 
  1097.            NULL);
  1098. }
  1099.  
  1100. /**********************************************************************
  1101.  * layout
  1102.  **********************************************************************/
  1103.  
  1104. static void Layout(Edit self,Widget parent,Cardinal stacking)
  1105. {
  1106.     Widget vbox, hbox,use;
  1107.     Widget editMenu, optionMenu;
  1108.  
  1109.     /*** shell ***/
  1110.     self->shell = XtVaCreatePopupShell 
  1111.       ("edit",topLevelShellWidgetClass, self->app->shell,
  1112.        XtNwidth,
  1113.        ((unsigned int)self->emap->mapx > self->app->res.mapWidth ?
  1114.     self->app->res.mapWidth * FONTSIZE :
  1115.     self->emap->mapx * FONTSIZE ) + 16,/* kludge */
  1116.        XtNheight,
  1117.        ((unsigned int)self->emap->mapy > self->app->res.mapHeight ?
  1118.     self->app->res.mapHeight * FONTSIZE :
  1119.     self->emap->mapy * FONTSIZE ) + 46,/* kludge */
  1120.        XtNiconPixmap,bitmaps.edit,
  1121.        NULL);
  1122.     vbox = XtVaCreateManagedWidget ("vbox", panedWidgetClass,
  1123.       self->shell, NULL);
  1124.  
  1125.     /*** menu bar ***/
  1126.     hbox = XtVaCreateManagedWidget ("hbox", boxWidgetClass,
  1127.       vbox, NULL);
  1128.     
  1129.     if(self->type != ClipBoard) {
  1130.     use = XtVaCreateManagedWidget 
  1131.         ("mapFileButton", menuButtonWidgetClass, hbox,
  1132.          XtNmenuName,"fileMenu",
  1133.          NULL);
  1134.     CnvMenu("fileMenu",use,fileMenu,(XtPointer)self);
  1135.  
  1136.     editMenu = XtVaCreateManagedWidget 
  1137.         ("mapEditButton", menuButtonWidgetClass, hbox,
  1138.          XtNmenuName,"mapEdit",
  1139.          NULL);
  1140.  
  1141.     optionMenu = XtVaCreateManagedWidget 
  1142.         ("mapOptionButton", menuButtonWidgetClass, hbox,
  1143.          XtNmenuName,"optionMenu",
  1144.          NULL);
  1145.     OptionMenu("optionMenu",self,optionMenu);
  1146.     }
  1147.  
  1148.  
  1149.     /*** editor-widget ***/
  1150.     self->view = XtVaCreateManagedWidget 
  1151.     ("veivi",viewportWidgetClass, vbox, 
  1152.      XtNallowResize,True,
  1153.      XtNforceBars,True,
  1154.      XtNallowHoriz,True,
  1155.      XtNallowVert,True,
  1156.      NULL);
  1157.     self->w = XtVaCreateManagedWidget 
  1158.     ("cross",crEditWidgetClass,self->view,
  1159.      XtNresizable,True,
  1160.      XtNmap,self->emap,
  1161.      XtNstacking,stacking,
  1162.      XtNselectArea,True,
  1163.      NULL);
  1164.     XtAddCallback(self->w,XtNinsertCallback,InsertCb,(XtPointer)self);
  1165.     XtAddCallback(self->w,XtNselectCallback,SelectCb,(XtPointer)self);
  1166.     XtAddCallback(self->w,XtNpropsCallback,PropsCb,(XtPointer)self);
  1167.     XtAddCallback(self->w,XtNdeleteCallback,DeleteCb,(XtPointer)self);
  1168.     XtAddCallback(self->w,XtNalignCallback,AlignCb,(XtPointer)self);
  1169.     XtAddCallback(self->w,XtNfeedCallback,FeedCb,(XtPointer)self);
  1170. }
  1171.  
  1172. /**********************************************************************
  1173.  * public
  1174.  **********************************************************************/
  1175.  
  1176. /*
  1177.  * create editing window for map for crossfire-abs-path file-name
  1178.  */
  1179. Edit EditCreate(App app,EditType type,String path)
  1180. {
  1181.     Edit self;
  1182.  
  1183.     /*** initialising ***/
  1184.     self = (Edit)XtMalloc(sizeof(struct _Edit));
  1185.     self->app = app;
  1186.     self->shell = NULL;
  1187.     self->w = NULL;
  1188.     self->view = NULL;
  1189.     self->next = NULL;
  1190.     self->emap = NULL;
  1191.     self->type = type;
  1192.     self->overwrite = 0;
  1193.     self->mapattr = 0;
  1194.  
  1195.     /*** load or create map ***/
  1196.     if (type == ClipBoard) {
  1197.     if (!self->emap)
  1198.         self->emap = get_empty_map(MapMinWidth,MapMinHeight);
  1199.     strcpy (self->emap->path, "/ClipBoard");
  1200.  
  1201.     } else if(path && *path != '\0') {
  1202.     if (!Load(self,path)) return 0;
  1203.     if(!strcmp(self->emap->map_object->name,"map")) /* Yak, no "map" */
  1204.           self->emap->map_object->name = MapNameCreate(path);
  1205.     } else {
  1206.     self->emap = get_empty_map(16,16);
  1207.     strcpy (self->emap->path, "/Noname");
  1208.     }
  1209.     
  1210.     if (!self->emap)
  1211.     return 0;
  1212.     
  1213.     if (!self->emap->map_object->msg) {
  1214.     self->emap->map_object->msg = MapMessageCreate (app);
  1215.     }
  1216.  
  1217.     /*** creating ***/
  1218.     Layout(self,self->app->shell,0);
  1219.     EditUnmodified(self);
  1220.  
  1221.     /*** type specific ***/
  1222.     switch (self->type) {
  1223.     case Regular:
  1224.     self->read_only = 0;
  1225.     self->auto_choose = 0;
  1226.     break;
  1227.     case Pick:
  1228.     case Wall:
  1229.     self->read_only = 1;
  1230.     self->auto_choose = 1;
  1231.     XtVaSetValues(self->w,
  1232.               XtNstacking,1,
  1233.               XtNselectArea,False,
  1234.               NULL);
  1235.     break;
  1236.     case ClipBoard:
  1237.     self->read_only = 0;
  1238.     self->auto_choose = 0;
  1239.     break;
  1240.     default:
  1241.         fprintf(stderr,"unknown MapType");
  1242.     exit(EXIT_FAILURE);
  1243.     }
  1244.     EditUpdate(self);
  1245.     /*** show-map-editor ***/
  1246.     if(type != ClipBoard)
  1247.     XtPopup (self->shell, XtGrabNone);
  1248.  
  1249.     return self;
  1250. }
  1251.  
  1252. /*
  1253.  * member: destroy edit
  1254.  */
  1255. void EditDestroy(Edit self)
  1256. {
  1257.     char buf[BUFSIZ];
  1258.     
  1259.     if(!self) return;
  1260.     debug1 ("EditDestroy() %s\n",EditGetPath(self));
  1261.     
  1262.     /*** reply to save if designed ***/
  1263.     if (EditIsModified(self)) {
  1264.     sprintf (buf, "Quitting, save %s ?", self->emap->path);
  1265.     switch (CnvNotify (buf,"Save","Forget",NULL)) {
  1266.     case 1:        /* ok */
  1267.         EditSave(self);
  1268.         break;
  1269.     default:
  1270.         break;
  1271.     }
  1272.     }
  1273.     /*** outer coonections ***/
  1274.     if (self->mapattr) {
  1275.     AttrDestroy (self->mapattr);
  1276.     }
  1277.     if (self->app->attr && self->app->attr->op &&
  1278.     self->app->attr->op->map == self->emap) {
  1279.     AttrChange(self->app->attr, NULL, 0, (Edit)0);
  1280.     }
  1281.     if (AppItemGetEdit(self->app) == self) {
  1282.     AppItemSet (self->app, NULL,NULL,0);
  1283.     }
  1284.     AppUpdate(self->app);
  1285.     AppEditDeattach(self->app,self);
  1286.     EdFreeMap (self);
  1287.  
  1288.     /*** inner remove ***/
  1289.     XtDestroyWidget (self->shell);
  1290.     XtFree((char*)self);
  1291. }
  1292.  
  1293. /*
  1294.  * member: update Edit values
  1295.  */
  1296. void EditUpdate(Edit self)
  1297. {
  1298.     char buf[BUFSIZ];
  1299.  
  1300.     if(!(self && self->shell && self->emap)) return;
  1301.  
  1302.     /*** map title ***/
  1303.     sprintf(buf,
  1304.         "Edit %s %s",
  1305.         self->emap->path,
  1306.         self->modified ? "*" : "");
  1307.     XtVaSetValues(self->shell,
  1308.           XtNtitle,buf,
  1309.           XtNiconName,buf,
  1310.           NULL);
  1311.     
  1312.     /*** info ***/
  1313.     if (self->mapattr)
  1314.     AttrChange (self->mapattr, self->emap->map_object, -1, self);
  1315.  
  1316.     /*** toggles ***/
  1317.     if(self->type != ClipBoard) {
  1318. #if 0
  1319.     XtVaSetValues 
  1320.         (self->iw.read_only,
  1321.          XtNleftBitmap, self->read_only ? bitmaps.mark : None, NULL);
  1322. #endif
  1323.     XtVaSetValues 
  1324.         (self->iw.overwrite, 
  1325.          XtNleftBitmap, self->overwrite ? bitmaps.mark : None, NULL);
  1326.     XtVaSetValues 
  1327.         (self->iw.auto_choose, 
  1328.          XtNleftBitmap, self->auto_choose ? bitmaps.mark : None, 
  1329.          NULL);
  1330.     }
  1331.     /*** map area ***/
  1332.     if(self->emap && self->w)
  1333.     XtVaSetValues(self->w,XtNmap,self->emap,NULL);
  1334.  
  1335.     if (self->app->look.edit == self)
  1336.     CrEditRefresh (self->w, self->app->look.rect);
  1337. }
  1338.  
  1339. /*
  1340.  * member : save map from memory to file, there should be no other
  1341.  *            map saving routine than self
  1342.  * self   : pointer to current Edit structure
  1343.  * name   : filename of map, relative ( level number )  ???
  1344.  * return : True, map is saved
  1345.  */
  1346. static Boolean EdSaveMap (Edit self, char *name)
  1347. {
  1348.     mapstruct *m = self->emap;
  1349.     char buf[BUFSIZ];
  1350.  
  1351.     debug0 ("Saving Map by name\n");
  1352.  
  1353.     strcpy (m->path, name);
  1354.  
  1355.     /*** updating map name here ***/
  1356.     EditSetPath(self,name);
  1357.     if(new_save_map (m, 1)) {
  1358.     sprintf(buf,"Error in saving map %s",EditGetPath(self));
  1359.     CnvNotify ("Error in saving map !","OK",NULL);
  1360.     return False;
  1361.     }
  1362.     EditUnmodified(self);
  1363.     return True;
  1364. }
  1365.  
  1366. /*
  1367.  * member: save contents of map to file
  1368.  * return: status
  1369.  */
  1370. EditReturn EditSave(Edit self)
  1371. {
  1372.     char path[PATH_MAX+1];  
  1373.  
  1374.     if (self->read_only) {
  1375.     CnvNotify ( "Map is read-only!","OK",NULL);
  1376.     return EditOk;
  1377.     }
  1378.     if (!self->modified) {
  1379.     CnvNotify ( "No changes to save", "OK",NULL);
  1380.     return EditOk;
  1381.     }
  1382.     /*** if empty path, ask it ***/
  1383.     if (!*self->emap->path) {
  1384.     if(CnvPathSelect(self->app->path) == CnvPathCancel) return EditOk;
  1385.     sprintf(path,"%s/%s",self->app->path->current,
  1386.         self->app->path->filename);
  1387.     strcpy (self->emap->path, path);
  1388.     }
  1389.     if(!EdSaveMap(self,self->emap->path)) return EditOk;
  1390.     EditUpdate(self);
  1391.     return EditOk;
  1392. }
  1393.  
  1394. /*
  1395.  * member: make fill
  1396.  * x,y   : point to start fill
  1397.  */
  1398. void EditPerformFill(Edit self, int x, int y)
  1399. {
  1400.     if (self->emap && 
  1401.     !out_of_map (self->emap, x, y) && 
  1402.     !get_map_ob(self->emap, x, y) &&
  1403.     EditInsert (self, x, y, 0)) {
  1404.     EditPerformFill (self, x+1, y);
  1405.     EditPerformFill (self, x+1, y+1);
  1406.     EditPerformFill (self, x, y+1);
  1407.     EditPerformFill (self, x-1, y+1);
  1408.     EditPerformFill (self, x-1, y);
  1409.     EditPerformFill (self, x-1, y-1);
  1410.     EditPerformFill (self, x, y-1);
  1411.     EditPerformFill (self, x+1, y-1);
  1412.     }
  1413. }
  1414.  
  1415. /*
  1416.  * member: fill
  1417.  * x,y   : point to start fill
  1418.  */
  1419. void EditFillRectangle(Edit self, XRectangle rec)
  1420. {
  1421.     int x,y;
  1422.  
  1423.     if (!self->emap || self->read_only)
  1424.     return;
  1425.  
  1426.     for(x = 0; x < rec.width; x++)
  1427.     for(y = 0; y < rec.height; y++)
  1428.         EditInsert (self, x + rec.x, y + rec.y, 0);
  1429.  
  1430.     return;
  1431. }
  1432.  
  1433.  
  1434. /*
  1435.  * member: wipe
  1436.  * x,y   : point to start fill
  1437.  */
  1438. void EditWipeRectangle(Edit self, XRectangle rec)
  1439. {
  1440.     int x,y;
  1441.  
  1442.     if (!self || !self->emap || self->read_only)
  1443.     return;
  1444.  
  1445.     for(x=0; x < rec.width; x++)
  1446.     for(y=0; y < rec.height; y++)
  1447.         while(get_map_ob(self->emap,x + rec.x, y + rec.y))
  1448.         EditObjectDelete (self, x + rec.x, y + rec.y, 0);
  1449.     CrEditRefresh (self->w, rec);
  1450.     return;
  1451. }
  1452.  
  1453. /*
  1454.  * member: shave
  1455.  * x,y   : point to start fill
  1456.  */
  1457. void EditShaveRectangle(Edit self, XRectangle rec)
  1458. {
  1459.     int x,y;
  1460.  
  1461.     if (!self || !self->emap || self->read_only)
  1462.     return;
  1463.  
  1464.     for(x=0; x < rec.width; x++)
  1465.     for(y=0; y < rec.height; y++)
  1466.         EditObjectDelete (self, x + rec.x, y + rec.y, 0);
  1467.  
  1468.     CrEditRefresh (self->w, rec);
  1469.     return;
  1470. }
  1471.  
  1472. /*
  1473.  * member: copy rectangle area (x,y,width,height) from src to
  1474.  *         self to point (x,y)
  1475.  */
  1476. void EditCopyRectangle(Edit self,Edit src,XRectangle rect,int sx,int sy)
  1477. {
  1478.     int x, y, z;
  1479.     object *obj,*tmp;
  1480.  
  1481.     if(!self || 
  1482.        !src ||
  1483.        self->read_only)
  1484.     return;
  1485.  
  1486.     if (rect.width > self->emap->mapx - sx)
  1487.     rect.width = self->emap->mapx - sx;
  1488.     if (rect.width > (unsigned int)src->emap->mapx)
  1489.     rect.width = src->emap->mapx;
  1490.  
  1491.     if (rect.height > self->emap->mapy - sy)
  1492.     rect.height = self->emap->mapy - sy;
  1493.     if (rect.height > (unsigned int)src->emap->mapy)
  1494.     rect.height = src->emap->mapy;
  1495.  
  1496.     debug2("EditCopyRectangle() %s -> %s\n",EditGetPath(src),
  1497.       EditGetPath(self));
  1498.     if(self->overwrite) 
  1499.     for(x=0; x < rect.width; x++)
  1500.         for(y=0; y < rect.height; y++)
  1501.         EditDeletePoint(self,(sx+x),(sy+y));
  1502.         
  1503.     for(x=0; x < rect.width; x++)
  1504.     for(y=0; y < rect.height; y++) {
  1505.         obj = MapGetObjectZ(src->emap,(rect.x + x),(rect.y + y),0);
  1506.         for(tmp = obj,z=0; tmp; tmp = tmp->below,z++) {
  1507.         if(tmp->head) {continue;}
  1508.         /*EditObjectInsert(self,tmp,(sx+x),(sy+y),z);*/
  1509.         EditCloneInsert(self,tmp,(sx+x),(sy+y),z);
  1510.         }
  1511.     }
  1512.     rect.x = sx;
  1513.     rect.y = sy;
  1514.     CrEditRefresh (self->w, rect);
  1515.     EditModified(self);
  1516. }
  1517.  
  1518. /*
  1519.  *
  1520.  */
  1521. void EditDeletePoint(Edit self,int x,int y)
  1522. {
  1523.     while(get_map_ob(self->emap,x,y))
  1524.     EditDelete(self,x,y,0);
  1525. }
  1526.  
  1527. /*
  1528.  * Member: set Edit to modified state
  1529.  */
  1530. void EditModified(Edit self)
  1531. {
  1532.     if (self && !self->modified) {
  1533.       self->modified = True;
  1534.       EditUpdate(self);
  1535.     }
  1536. }
  1537.  
  1538. /*
  1539.  * member: set Edit to modified state
  1540.  */
  1541. void EditUnmodified(Edit self)
  1542. {
  1543.     if (self && self->modified) {
  1544.       self->modified = False;
  1545.       EditUpdate(self);
  1546.     }
  1547. }
  1548.  
  1549. static void EditObjectCalc(Edit self,object *obj,XRectangle *rect)
  1550. {
  1551.     object *tmp;
  1552.  
  1553.     rect->x = 10000;
  1554.     rect->y = 10000;
  1555.     rect->width = 0;
  1556.     rect->height = 0;
  1557.     for (tmp = obj; tmp; tmp = tmp->more) {
  1558.     if (self->app->look.rect.x == tmp->x && 
  1559.         self->app->look.rect.y == tmp->y)
  1560.         AppUpdate(self->app);
  1561.     if(tmp->x < rect->x) rect->x = tmp->x;
  1562.     if(tmp->y < rect->y) rect->y = tmp->y;
  1563.     if(tmp->x - rect->x + 1> rect->width) 
  1564.         rect->width = tmp->x - rect->x + 1;
  1565.     if(tmp->y - rect->y + 1> rect->height) 
  1566.         rect->height = tmp->y - rect->y + 1;
  1567.     }
  1568. }
  1569.  
  1570. /*
  1571.  * member: delete object from map of editor
  1572.  * x,y,z : delete object from self point
  1573.  * return: True, if object deleted
  1574.  */
  1575. Boolean EditDelete (Edit self, int x, int y, int z)
  1576. {
  1577.     object *obj;
  1578.     XRectangle rect;
  1579.  
  1580.     obj = MapGetObjectZ(self->emap, x, y, z);
  1581.     if (self->read_only || z < 0 || !obj)
  1582.       return False;
  1583.     if (obj->head)
  1584.     obj = obj->head;
  1585.  
  1586.     EditObjectCalc (self,obj,&rect);
  1587.     if (!EditObjectDelete (self, x, y, z))
  1588.       return False;
  1589.     CrEditRefresh (self->w,rect);
  1590.  
  1591.     if (self->app->item.wall_map)
  1592.     draw_remove (self, x, y);
  1593.     
  1594.     EditModified(self);
  1595.     return True;
  1596. }
  1597.  
  1598. /*
  1599.  * member: delete object from map of editor
  1600.  * x,y,z : delete object from self point
  1601.  * return: True, if object deleted
  1602.  */
  1603. Boolean EditObjectDelete (Edit self, int x, int y, int z)
  1604. {
  1605.     object *obj;
  1606.  
  1607.     obj = MapGetObjectZ(self->emap, x, y, z);
  1608.     if (self->read_only || z < 0 || !obj)
  1609.       return False;
  1610.  
  1611.     if (obj->head)
  1612.     obj = obj->head;
  1613.     if (self->app->attr && self->app->attr->op == obj)
  1614.     AttrChange(self->app->attr, NULL, 0, 0);
  1615.     if (AppItemGetEdit(self->app) == self)
  1616.       AppItemSet (self->app, NULL,NULL,0);
  1617.  
  1618.     debug4("EditDelete() %s in %dx%dx%d\n",obj->name,x, y, z);
  1619.  
  1620.     remove_ob (obj);
  1621.     free_object (obj);
  1622.     update_position (self->emap, x, y);
  1623.     return True;
  1624. }
  1625.  
  1626. /*
  1627.  * member: insert object to point of map of editor
  1628.  * object:
  1629.  * x,y,z : point to insert
  1630.  * return: True, if obejct inserted
  1631.  */
  1632. object *EditCloneInsert (Edit self,object *obj,int x, int y, int z)
  1633. {
  1634.     object *op;
  1635.     int button_value;
  1636.  
  1637.     /*** create & insert ***/
  1638.     if ((op = ObjectCreateClone(obj))) {
  1639.     /*** object do not fit ***/
  1640.     if(!MapObjectOut(self->emap,op,x,y)) {
  1641.         MapInsertObjectZ (self->emap, op, x, y, z);
  1642.         if (QUERY_FLAG(obj, FLAG_IS_LINKED) && 
  1643.           (button_value = get_button_value(obj))) {
  1644.         add_button_link(op, self->emap, button_value);
  1645.           }
  1646.         return op;
  1647.     }
  1648.     } 
  1649.     debug0 ("Inserting failed\n");
  1650.     return NULL;
  1651. }
  1652.  
  1653. /*
  1654.  * member: insert object to point of map of editor
  1655.  * x,y,z : point to insert
  1656.  * return: True, if obejct inserted
  1657.  */
  1658. Boolean EditInsert (Edit self,int x, int y, int z)
  1659. {
  1660.     int zi = z;
  1661.     object *op,*tmp;
  1662.     XRectangle rect;
  1663.  
  1664.     /*** ***/
  1665.     if (!self ||
  1666.     self->read_only ||
  1667.     !self->emap || 
  1668.     out_of_map (self->emap, x, y))
  1669.     return False;
  1670.  
  1671.     /*** something to insert ***/
  1672.     if (!AppItemGetObject(self->app) && !AppItemGetMap(self->app)) {
  1673.     CnvNotify ( "Select item to insert.", "OK", NULL);
  1674.     return False;
  1675.     }
  1676.     /*** check for duplicate object ***/
  1677.     if (z >= 0) {
  1678.     op = get_map_ob (self->emap, x, y);
  1679.     while (op && op->above)
  1680.         op = op->above;
  1681.     while (op && zi-- > 0)
  1682.         op = op->below;
  1683.     if (op && op->arch == self->app->item.clone->arch)
  1684.         return False;
  1685.     }
  1686.  
  1687.     debug3("EditInsert() %dx%dx%d\n",x,y,z);
  1688.  
  1689.     /*** handle background ***/
  1690.     if (self->overwrite)
  1691.     while (get_map_ob (self->emap, x, y))
  1692.         EditDelete(self, x, y, 0);
  1693.     else {
  1694.     tmp = MapGetObjectZ (self->emap, x, y, z);
  1695.     if (tmp && 
  1696.         (tmp->arch == self->app->item.clone->arch ||
  1697.         (self->app->item.wall_map &&
  1698.           find_draw_arch (AppItemGetMap(self->app),
  1699.         AppItemGetWall(self->app),
  1700.         tmp->arch) >= 0)))
  1701.         return False;
  1702.     }
  1703.  
  1704.     /*** create & insert ***/
  1705.     op = EditCloneInsert (self, self->app->item.clone, x, y, z);
  1706.  
  1707.     if (self->app->item.wall_map) 
  1708.     draw_add (self, x, y);
  1709.  
  1710.     EditObjectCalc(self,op,&rect);
  1711.     CrEditRefresh(self->w,rect);
  1712.     update_position (self->emap, x, y);
  1713.  
  1714.     EditModified(self);
  1715.     return True;
  1716. }
  1717.  
  1718.  
  1719.  
  1720. /*
  1721.  * member: insert object to point of map of editor
  1722.  * object:
  1723.  * x,y,z : point to insert
  1724.  * return: True, if obejct inserted
  1725.  */
  1726. Boolean EditObjectInsert (Edit self,object *obj,int x, int y, int z)
  1727. {
  1728.     int zi = z;
  1729.     object *op,*tmp;
  1730.     XRectangle rect;
  1731.  
  1732.     /*** ***/
  1733.     if (!self ||
  1734.     self->read_only ||
  1735.     !self->emap || 
  1736.     out_of_map (self->emap, x, y) ||
  1737.     !obj)
  1738.     return False;
  1739.  
  1740.     /*** check for duplicate object ***/
  1741.     op = get_map_ob (self->emap, x, y);
  1742.     while (op && op->above)
  1743.     op = op->above;
  1744.     while (op && zi-- > 0)
  1745.     op = op->below;
  1746.     if (op && op->arch == obj->arch)
  1747.     return False;
  1748.  
  1749.     debug3("EditInsert() %dx%dx%d\n",x,y,z);
  1750.  
  1751.     /*** handle background ***/
  1752.     tmp = MapGetObjectZ (self->emap, x, y, z);
  1753.     if (tmp && (tmp->arch == obj->arch))
  1754.     return False;
  1755.     
  1756.     /*** create & insert ***/
  1757.     op = EditCloneInsert (self, op, x, y, z);
  1758.  
  1759.     EditObjectCalc(self,op,&rect);
  1760.     CrEditRefresh(self->w,rect);
  1761.  
  1762.     EditModified(self);
  1763.     return True;
  1764. }
  1765.  
  1766. /*
  1767.  * member: set path name of map
  1768.  * path  : path of file representing map
  1769.  */
  1770. void EditSetPath(Edit self,String path)
  1771. {
  1772.     if(!self) return;
  1773.     strcpy(self->emap->path,path);
  1774.     EditUpdate(self);
  1775. }
  1776.  
  1777. /*** end of Edit.c ***/
  1778.  
  1779.